/**
 * 
 */
package mm.front.jsf.mb;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.xml.bind.ValidationException;

import mm.back.entity.Producto;
import mm.back.entity.Rubro;
import mm.back.filtros.ProductosFiltro;
import mm.back.service.ProductoService;
import mm.back.service.RubroService;
import mm.exceptions.MMGenericException;
import mm.exceptions.MMInvalidIDException;
import mm.front.jsf.ConstantesOutcome;
import mm.front.jsf.JSFUtils;

/**
 * @author PUSDERKIS
 *
 */
public class ProductosManagedBean extends MMAbstractManagedBean implements Serializable {
	
	private static final String SESSION_PROD_FILTER="mm.productosManagedBean.prodFilter"; 
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5808249726283545164L;
	private transient ProductoService productoService;
	private transient RubroService rubroService;
	private Producto producto;
	private ProductosFiltro prodFilter;
	private Long rubro;
	private String filtroNombre;
	private boolean createOk;
	private boolean isModificacion;
	private boolean isAdicion;
	private boolean isSustraccion;
	private String detalleSustraccion;
	private BigDecimal cantidad;
	private Long idProducto;
	
	/**
	 * @return the cantidad
	 */
	public BigDecimal getCantidad() {
		return cantidad;
	}
	
	/**
	 * @param cantidad the cantidad to set
	 */
	public void setCantidad(BigDecimal cantidad) {
		this.cantidad = cantidad;
	}
	

	private Long prodToDelete;
	
	private List<Producto> listaProductos;
	
	int comparar = 0;
	
	public String guardarProducto(){
		
		Rubro rubro = rubroService.getRubro(getRubro());
		
		getProducto().setRubro(rubro);
		getProducto().setActivo(true);
		
		if (validateProducto(getProducto())){
			try{
				productoService.createProducto(getProducto());
				JSFUtils.addInfoMessage("Se guardo con exito el producto.");
				return ConstantesOutcome.PRODUCTO_LISTADO;
			}catch (MMGenericException e) {
				JSFUtils.addErrorMessage(e.getMessage());
			}
		}
		
		return null;
	}
	
	public String buscarProductos(ProductosFiltro pf){
		
		pf.setActivo(Boolean.TRUE);
		pf.setRubroActivo(Boolean.TRUE);
		List<Producto> prodList = productoService.getProductos(pf);
		
		setListaProductos(prodList);
		
		return null;
	}
		
	public String nuevoProducto(){
		producto = new Producto();
		setCreateOk(false);
		return ConstantesOutcome.PRODUCTO_ALTA;
	}

	public void borrarProducto(){
		
		if (prodToDelete != null && prodToDelete != 0){
			productoService.deleteProducto(prodToDelete);
			buscarProductos(getProdFilter());
		}
		
	}
	
	public String modificarProducto(){

		Rubro rubro = rubroService.getRubro(getRubro());
		
		getProducto().setRubro(rubro);
		getProducto().setActivo(true);
		
		if (validateProducto(getProducto())){
			try{
				productoService.saveProducto(getProducto());
				JSFUtils.addInfoMessage("Se guardo con exito el producto.");
				return ConstantesOutcome.PRODUCTO_LISTADO;
			}catch (MMGenericException e) {
				JSFUtils.addErrorMessage(e.getMessage());
			}
		}
		return null;
	}
	
	public String modificarProductoInit(){
		isModificacion = false;
		producto = productoService.getProducto(producto.getId());
		rubro = producto.getRubro().getId();
		return ConstantesOutcome.PRODUCTO_MODIFICAR;
	}
	
	public String devolucionProductoInit(Long idProd){
		producto = productoService.getProducto(idProd);
		return "devolucionProducto";
	}
	
	public String verDetalleProducto(Long idProd){
		if (idProd == null){
			throw new MMInvalidIDException("No se puede recuperar la venta número: "+idProd);
		}
		setIdProductos(idProd);


		return ConstantesOutcome.PRODUCTO_DEVOLUCION;
	}
	
	public Long getIdProducto() {
		return idProducto;
	}

	/**
	 * @param idVenta the idVenta to set
	 */
	public void setIdProductos(Long idProd) {
		this.idProducto = idProd;
	}
	
	
	
	public String listadoProductosInit(){
		ProductosFiltro pf = new ProductosFiltro();
		pf.setActivo(true);
		setProdFilter(pf);
		return ConstantesOutcome.PRODUCTO_LISTADO;
	}
	
	public String adicionarInit(Long id){
		getProducto().setId(id);
		buscarProductos(getProdFilter());
		return adicionarInit();
		/**
		 * TODO ver aca!!
		 * 
		 */
	}
	
	public String adicionarInit(){
		producto = productoService.getProducto(getProducto().getId());
		setAdicion(true);
		return null;
	}
	
	public void adicionarCancel(){
		setAdicion(false);
	}
	
	public String adicionar(){
		Producto prod = getProductoReloaded();
		
		BigDecimal stock = cantidad.add(prod.getStock());
		
		
//TODO pasar a validador
		if (BigDecimal.ZERO.compareTo(cantidad) > -1){
			addErrorMessage("cantidad", "La cantidad no puede ser menor que 0.");
			setAdicion(true);
		}
		
		if (stock.compareTo(prod.getStockMax()) > 0){
			FacesMessage fm = new FacesMessage("Se intento agregar mas stock del permitido.");
			fm.setSeverity(FacesMessage.SEVERITY_ERROR);
			FacesContext.getCurrentInstance().addMessage("adicionModalPanel", fm);
			setAdicion(true);
		} else if(!(BigDecimal.ZERO.compareTo(getProducto().getPrecioCompra()) > -1) && !(BigDecimal.ZERO.compareTo(cantidad) > -1)){
			prod.setStock(stock);
			prod.setPrecioCompra(getProducto().getPrecioCompra());
			productoService.saveProducto(prod);
			addInfoMessage(null, "Se agrego con exito el stock al producto.");
			setAdicion(false);
		}
		buscarProductos(getProdFilter());
		return ConstantesOutcome.PRODUCTO_LISTADO;
	}
	
	
	public String restarInit(Long id){
		producto = productoService.getProducto(id);
		setDetalleSustraccion(null);
		setSustraccion(true);
		return null;
	}
	
	
	public void restarCancel(){
		setSustraccion(false);
	}
	
	public String restar(BigDecimal cantidad, String motivo) {
		
		try{
			productoService.registrarBajaStock(getProducto().getId(), cantidad, motivo);
			buscarProductos(getProdFilter());
			
			setSustraccion(false);
			addInfoMessage(null, "Se registro con exito la baja de stock.");
			
		} catch (MMGenericException e) {
			addErrorMessage(null, e.getMessage());
		}
		
		return ConstantesOutcome.PRODUCTO_LISTADO;
	}
	
	
	public String devolverProducto(){
		productoService.registrarDevolucion(producto.getId(), cantidad);
		
		JSFUtils.addInfoMessage("Se registro la devolución con exito");
		return ConstantesOutcome.PRODUCTO_LISTADO;
	}
	
	private Producto getProductoReloaded(){
		return productoService.getProducto(getProducto().getId());
	}
	
	/**
	 * @return the producto
	 */
	public Producto getProducto() {
		return producto;
	}

	/**
	 * @param producto the producto to set
	 */
	public void setProducto(Producto producto) {
		this.producto = producto;
	}

	/**
	 * @param productoService the productoService to set
	 */
	public void setProductoService(ProductoService productoService) {
		this.productoService = productoService;
	}

	/**
	 * @return the rubro
	 */
	public Long getRubro() {
		return rubro;
	}

	/**
	 * @param rubro the rubro to set
	 */
	public void setRubro(Long rubro) {
		this.rubro = rubro;
	}

	/**
	 * @param rubroService the rubroService to set
	 */
	public void setRubroService(RubroService rubroService) {
		this.rubroService = rubroService;
	}

	/**
	 * @return the filtroNombre
	 */
	public String getFiltroNombre() {
		return filtroNombre;
	}

	/**
	 * @param filtroNombre the filtroNombre to set
	 */
	public void setFiltroNombre(String filtroNombre) {
		this.filtroNombre = filtroNombre;
	}

	/**
	 * @return the createOk
	 */
	public boolean isCreateOk() {
		return createOk;
	}

	/**
	 * @param createOk the createOk to set
	 */
	public void setCreateOk(boolean createOk) {
		this.createOk = createOk;
	}

	/**
	 * @return the prodFilter
	 */
	public ProductosFiltro getProdFilter() {
		
		if (prodFilter == null){
			if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey(SESSION_PROD_FILTER)){
				prodFilter = new ProductosFiltro();
				setProdFilter(prodFilter);
			} else {
				prodFilter = (ProductosFiltro) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(SESSION_PROD_FILTER);
			}
		}
		
		return prodFilter;
	}

	/**
	 * @param prodFilter the prodFilter to set
	 */
	public void setProdFilter(ProductosFiltro prodFilter) {
		
		FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(SESSION_PROD_FILTER, prodFilter);
		
		this.prodFilter = prodFilter;
	}

	/**
	 * @return the listaProductos
	 */
	public List<Producto> getListaProductos() {
		if (listaProductos == null){
			buscarProductos(getProdFilter());
		}
		return listaProductos;
	}

	/**
	 * @param listaProductos the listaProductos to set
	 */
	public void setListaProductos(List<Producto> listaProductos) {
		this.listaProductos = listaProductos;
	}

	/**
	 * @return the prodToDelete
	 */
	public Long getProdToDelete() {
		return prodToDelete;
	}

	/**
	 * @param prodToDelete the prodToDelete to set
	 */
	public void setProdToDelete(Long prodToDelete) {
		this.prodToDelete = prodToDelete;
	}

	/**
	 * @return the isModificacion
	 */
	public boolean isModificacion() {
		return isModificacion;
	}

	/**
	 * @param isModificacion the isModificacion to set
	 */
	public void setModificacion(boolean isModificacion) {
		this.isModificacion = isModificacion;
	}
	

	/**
	 * @return the detalleSustraccion
	 */
	public String getDetalleSustraccion() {
		return detalleSustraccion;
	}

	/**
	 * @param detalleSustraccion the detalleSustraccion to set
	 */
	public void setDetalleSustraccion(String detalleSustraccion) {
		this.detalleSustraccion = detalleSustraccion;
	}

	/**
	 * @return the isSustraccion
	 */
	public boolean isSustraccion() {
		return isSustraccion;
	}

	/**
	 * @param isSustraccion the isSustraccion to set
	 */
	public void setSustraccion(boolean isSustraccion) {
		this.isSustraccion = isSustraccion;
	}


	

	/**
	 * @return the isAdicion
	 */
	public boolean isAdicion() {
		return isAdicion;
	}

	/**
	 * @param isAdicion the isAdicion to set
	 */
	public void setAdicion(boolean isAdicion) {
		this.isAdicion = isAdicion;
	}	
	
	/**
	 * VALIDADORES
	 * @throws ValidationException 
	 */
	
	public void validatePrecioCompra(FacesContext context, UIComponent component, Object value) throws ValidationException{
		if (BigDecimal.ZERO.compareTo((BigDecimal)value) > -1){
			setAdicion(true);
			((UIInput)component).setValid(false);
			addErrorMessage(component.getClientId(context), "El valor ingresado para el precio de compra debe ser mayor a 0.");
		} else {
			((UIInput)component).setValid(true);
		}
	}
	
	/**
	 * valida los datos del producto.
	 * @param p el producto.
	 * @return true si valido bien.
	 */
	public boolean validateProducto(Producto p){
		boolean valido = true;
		
		if (p.getRubro() == null || p.getRubro() == null || p.getRubro().getId() <= 0){
			JSFUtils.addErrorMessage("El campo rubro es requerido.");
			valido = false;
		}
		
		if(p.getStockMin().compareTo(producto.getStockMax()) >= comparar){
			JSFUtils.addErrorMessage("El stock minimo no puede ser superior al stock maximo.");
			valido = false;
		}
		if(producto.getStock().compareTo(producto.getStockMax()) > 0){		
			
			FacesMessage fm = new FacesMessage("Se intento agregar mas stock del permitido.");
			fm.setSeverity(FacesMessage.SEVERITY_ERROR);
			FacesContext.getCurrentInstance().addMessage("adicionModalPanel", fm);
			setAdicion(true);
			valido = false;
		}
		
		return valido; 
	}

}
